package cn.vehicle.interceptor;

import cn.vehicle.annotations.NoAuthCheck;
import cn.vehicle.domains.entity.SysPermissionEntity;
import cn.vehicle.domains.entity.SysUserEntity;
import cn.vehicle.domains.info.UserInfo;
import cn.vehicle.enums.PermissionTypeEnum;
import cn.vehicle.service.SysUserService;
import cn.vehicle.threadLocal.UserContextThreadLocal;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.List;

/**
 * 权限拦截器
 * <p>
 * 在请求进入 Controller 前执行权限校验逻辑。
 * 主要职责：
 * <ul>
 *   <li>根据 Token 中的用户信息，加载用户角色与权限；</li>
 *   <li>过滤非 API 类型的权限；</li>
 *   <li>校验当前请求 URI 是否匹配用户所拥有的权限码；</li>
 *   <li>支持通过 {@link cn.vehicle.annotations.NoAuthCheck} 注解跳过校验。</li>
 * </ul>
 * </p>
 */
@Component
public class PermissionInterceptor implements HandlerInterceptor {

    @Resource
    private SysUserService sysUserService;

    /**
     * 请求预处理方法
     * <p>在 Controller 执行前校验用户权限。</p>
     *
     * @param request  当前 HTTP 请求对象
     * @param response 当前 HTTP 响应对象
     * @param handler  即将执行的目标方法
     * @return true 表示继续执行，false 表示拦截请求
     * @throws Exception 异常信息
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 从请求属性中获取用户ID（由 JwtInterceptor 提前注入）
        Integer userId = (Integer) request.getAttribute("userId");
        UserInfo userInfo = new UserInfo();
        userInfo.setId(Long.valueOf(userId));

        // 查询用户基础信息并封装到 UserInfo 对象
        SysUserEntity userEntity = sysUserService.getUserById(Long.valueOf(userId));
        userInfo.setSysUserEntity(userEntity);

        // 判断当前方法或类上是否存在 @NoAuthCheck 注解，存在则跳过权限校验
        HandlerMethod method = (HandlerMethod) handler;
        if (method.getMethodAnnotation(NoAuthCheck.class) != null
            || method.getBeanType().getAnnotation(NoAuthCheck.class) != null) {
            UserContextThreadLocal.setUserInfo(userInfo);
            return true;
        };

        // 获取当前请求的 URI，用于匹配权限码
        String requestURI = request.getRequestURI();

        // 获取当前用户的角色与权限信息
        UserInfo userRoleAndPermission = sysUserService.getUserRoleAndPermission(Long.valueOf(userId));
        List<SysPermissionEntity> permissionEntityList = userRoleAndPermission.getPermissionEntityList();

        // 仅保留类型为 API 的权限项，用于接口访问控制
        permissionEntityList = permissionEntityList.stream()
                .filter(sysPermissionEntity
                        -> PermissionTypeEnum.API.name().equals(sysPermissionEntity.getPermissionType())).toList();

        // 遍历权限列表，判断当前请求是否在用户权限范围内
        boolean flag = false;
        for (SysPermissionEntity sysPermissionEntity : permissionEntityList) {
            if (requestURI.equals(sysPermissionEntity.getPermissionCode())) {
                flag = true;
                break;
            }
        }

        // 若未匹配到权限，则返回 401 未授权错误响应
        if (!flag) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write("{\"code\": \"100010\",\"message\": \"没有此接口权限\"}");
            return false;
        }

        userInfo.setPermissionEntityList(permissionEntityList);
        userInfo.setRoleEntityList(userRoleAndPermission.getRoleEntityList());

        // 将用户信息放入线程上下文，便于后续业务逻辑使用
        UserContextThreadLocal.setUserInfo(userInfo);

        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    /**
     * 请求完成后回调
     * <p>清理 ThreadLocal 中的用户信息，防止内存泄漏。</p>
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserContextThreadLocal.remove();

        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
